package com.nolon.flange.viewmodel

import android.view.View
import androidx.databinding.BaseObservable
import androidx.databinding.Observable
import androidx.databinding.ObservableArrayList
import androidx.databinding.ObservableField
import com.nolon.flange.R
import com.nolon.flange.extensions.toast
import com.nolon.flange.model.Flange
import com.nolon.flange.model.Order
import com.nolon.flange.model.Part
import com.nolon.flange.tools.F
import com.nolon.flange.tools.I

class OrderViewModel() :
    BaseObservable() {
    var id: Int = 0

    val len: ObservableField<String> = ObservableField("")

    val wid: ObservableField<String> = ObservableField("")

    val extraLen: ObservableField<String> = ObservableField("")

    val extraWid: ObservableField<String> = ObservableField("")

    val selectedSpecPosition: ObservableField<Int> = ObservableField(0)

    val specs: ObservableArrayList<String> = ObservableArrayList<String>().apply {
        addAll(listOf("30", "40", "50"))
    }

    val actualSpec: ObservableField<String> = ObservableField("30")

    val hasRounding: ObservableField<Boolean> = ObservableField(true)

    // 大孔数
    val xBigHoles: ObservableField<String> = ObservableField("")

    // 大孔边距
    val xBigHolePadding: ObservableField<String> = ObservableField("")

    // 大孔中心距离
    val xBigHoleDistance: ObservableField<String> = ObservableField("")
    val xSmallHoles: ObservableField<String> = ObservableField("")
    val xSmallHolePadding: ObservableField<String> = ObservableField("")

    val xSmallHoleDistance: ObservableField<String> = ObservableField("")
    val yBigHoles: ObservableField<String> = ObservableField("")
    val yBigHolePadding: ObservableField<String> = ObservableField("")

    val yBigHoleDistance: ObservableField<String> = ObservableField("")
    val ySmallHoles: ObservableField<String> = ObservableField("")
    val ySmallHolePadding: ObservableField<String> = ObservableField("")

    val ySmallHoleDistance: ObservableField<String> = ObservableField("")

    val num: ObservableField<String> = ObservableField("")

    val isClearAfterSave: ObservableField<Boolean> = ObservableField(true)

    val isPaddingFirst: ObservableField<Boolean> = ObservableField(true)

    val isHoleParamOpen: ObservableField<Boolean> = ObservableField(false)

    val holeParamVisibility: ObservableField<Int> = ObservableField(View.GONE)

    val extraVisibility: ObservableField<Int> = ObservableField(View.VISIBLE)

    fun toggleHoleParam(v: View) {
        holeParamVisibility.set(if (holeParamVisibility.get() == View.VISIBLE) View.GONE else View.VISIBLE)
        isHoleParamOpen.set(!isHoleParamOpen.get()!!)
    }

    val btnCancelVisible: ObservableField<Int> = ObservableField(View.GONE)

    val isAddingNew: ObservableField<Boolean> = ObservableField(true)

    fun getOrder(v: View): Order? {
        val len = len.get().I
        val wid = wid.get().I

        if (len <= 0f || wid <= 0f) return null.also {
            toast(v.context, v.context.getString(R.string.wrong_flange_params))
        }

        if (len < wid) return null.also {
            toast(v.context, v.context.getString(R.string.len_less_than_wid))
        }

        val spec = specs[selectedSpecPosition.get()!!]
        val actualSpec = actualSpec.get().I

        if (actualSpec <= 0f) return null.also {
            toast(v.context, v.context.getString(R.string.actual_spec_wrong))
        }

        val eLen = extraLen.get().I
        val eWid = extraWid.get().I
        if (eLen < 0f || eWid < 0f) return null.also {
            toast(v.context, v.context.getString(R.string.extra_wrong))
        }

        val requiredNum = num.get().I
        if (requiredNum == 0) return null.also {
            toast(v.context, v.context.getString(R.string.num_not_zero))
        }

        if (holeParamVisibility.get() == View.VISIBLE) {
            val xBig = xBigHoles.get().I
            val xBigPadding = xBigHolePadding.get().F
            val xBigDistance = xBigHoleDistance.get().F
            if (xBig == 0 || xBigPadding < 0f || xBigDistance <= 0f) return null.also {
                toast(v.context, v.context.getString(R.string.check_hole))
            }

            val xSmall = xSmallHoles.get().I
            val xSmallPadding = xSmallHolePadding.get().F
            val xSmallDistance = xSmallHoleDistance.get().F

            if (xSmall == 0 || xSmallPadding < 0f || xSmallDistance <= 0f) return null.also {
                toast(v.context, v.context.getString(R.string.check_hole))
            }

            val yBig = yBigHoles.get().I
            val yBigPadding = yBigHolePadding.get().F
            val yBigDistance = yBigHoleDistance.get().F
            if (yBig == 0 || yBigPadding < 0f || yBigDistance <= 0f) return null.also {
                toast(v.context, v.context.getString(R.string.check_hole))
            }

            val ySmall = ySmallHoles.get().I
            val ySmallPadding = ySmallHolePadding.get().F
            val ySmallDistance = ySmallHoleDistance.get().F
            if (ySmall == 0 || ySmallPadding < 0f || ySmallDistance <= 0f) return null.also {
                toast(v.context, v.context.getString(R.string.check_hole))
            }

            clearTable()

            val flange = Flange(
                length = len,
                width = wid,
                extraLength = eLen,
                extraWidth = eWid,
                materialSpec = spec,
                actualSpec = actualSpec,
                hasRounding = hasRounding.get()!!,
                // xBig
                xBigHoleCount = xBig,
                xBigHolePadding = xBigPadding,
                xBigHoleDistance = xBigDistance,
                // xSmall
                xSmallHoleCount = xSmall,
                xSmallHolePadding = xSmallPadding,
                xSmallHoleDistance = xSmallDistance,
                // yBig
                yBigHoleCount = yBig,
                yBigHolePadding = yBigPadding,
                yBigHoleDistance = yBigDistance,
                // ySmall
                ySmallHoleCount = ySmall,
                ySmallHolePadding = ySmallPadding,
                ySmallHoleDistance = ySmallDistance
            )
            return Order(id, 0, flange, requiredNum).also {
                if (id != 0) {
                    id = 0
                    isAddingNew.set(true)
                    btnCancelVisible.set(View.GONE)
                }
            }
        }
        clearTable()
        val flange = Flange(
            length = len,
            width = wid,
            extraLength = eLen,
            extraWidth = eWid,
            materialSpec = spec,
            actualSpec = actualSpec,
            hasRounding = hasRounding.get()!!,
        )
        return Order(id, 0, flange, requiredNum).also {
            if (id != 0) {
                id = 0
                isAddingNew.set(true)
                btnCancelVisible.set(View.GONE)
            }
        }
    }

    private fun clearTable() {
        if (isClearAfterSave.get()!!) {
            len.set("")
            wid.set("")
            extraLen.set("")
            extraWid.set("")
            xBigHoles.set("")
            yBigHoles.set("")
            num.set("")
        }
        xBigHoles.set("")
        xBigHolePadding.set("")
        xBigHoleDistance.set("")
        xSmallHoles.set("")
        xSmallHolePadding.set("")
        xSmallHoleDistance.set("")
        yBigHoles.set("")
        yBigHolePadding.set("")
        yBigHoleDistance.set("")
        ySmallHoles.set("")
        ySmallHolePadding.set("")
        ySmallHoleDistance.set("")
    }

    fun addOnChangeCallback() {
        // 规格Callback
        val changeCallback = object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
                actualSpec.set(specs[selectedSpecPosition.get()!!])
            }
        }
        selectedSpecPosition.addOnPropertyChangedCallback(changeCallback)

        xBigHoles.addOnPropertyChangedCallback(xBigCallback)
        xSmallHoles.addOnPropertyChangedCallback(xSmallCallback)
        yBigHoles.addOnPropertyChangedCallback(yBigCallback)
        ySmallHoles.addOnPropertyChangedCallback(ySmallCallback)

        if (isPaddingFirst.get()!!) {
            onPaddingFirstClick()
        } else {
            onDistanceFirstClick()
        }
    }

    private val xBigCallback =
        getCallBackObject(Part.DIRECTION_LENGTH, xBigHoles, xBigHolePadding, xBigHoleDistance)

    private val xSmallCallback =
        getCallBackObject(
            Part.DIRECTION_LENGTH,
            xSmallHoles,
            xSmallHolePadding,
            xSmallHoleDistance
        )

    private val yBigCallback =
        getCallBackObject(Part.DIRECTION_WIDTH, yBigHoles, yBigHolePadding, yBigHoleDistance)

    private val ySmallCallback =
        getCallBackObject(
            Part.DIRECTION_WIDTH,
            ySmallHoles,
            ySmallHolePadding,
            ySmallHoleDistance
        )

    fun onPaddingFirstClick() {
        isPaddingFirst.set(true)
        // remove
        xBigHoleDistance.removeOnPropertyChangedCallback(xBigCallback)
        xSmallHoleDistance.removeOnPropertyChangedCallback(xSmallCallback)
        yBigHoleDistance.removeOnPropertyChangedCallback(yBigCallback)
        ySmallHoleDistance.removeOnPropertyChangedCallback(ySmallCallback)
        // add
        xBigHolePadding.addOnPropertyChangedCallback(xBigCallback)
        xSmallHolePadding.addOnPropertyChangedCallback(xSmallCallback)
        yBigHolePadding.addOnPropertyChangedCallback(yBigCallback)
        ySmallHolePadding.addOnPropertyChangedCallback(ySmallCallback)
    }


    fun onDistanceFirstClick() {
        isPaddingFirst.set(false)
        // remove
        xBigHolePadding.removeOnPropertyChangedCallback(xBigCallback)
        xSmallHolePadding.removeOnPropertyChangedCallback(xSmallCallback)
        yBigHolePadding.removeOnPropertyChangedCallback(yBigCallback)
        ySmallHolePadding.removeOnPropertyChangedCallback(ySmallCallback)
        // add
        xBigHoleDistance.addOnPropertyChangedCallback(xBigCallback)
        xSmallHoleDistance.addOnPropertyChangedCallback(xSmallCallback)
        yBigHoleDistance.addOnPropertyChangedCallback(yBigCallback)
        ySmallHoleDistance.addOnPropertyChangedCallback(ySmallCallback)
    }

    private fun getCallBackObject(
        direction: Int,
        holes: ObservableField<String>,
        padding: ObservableField<String>,
        distance: ObservableField<String>
    ): Observable.OnPropertyChangedCallback {
        return object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
                val l =
                    if (direction == Part.DIRECTION_LENGTH) len.get().I + extraLen.get().I
                    else wid.get().I + extraWid.get().I
                val c = holes.get().I
                if (l < 10 || c < 1) return
                if (isPaddingFirst.get()!!) {
                    val p = padding.get().I
                    val d = (l - 2 * p) / c
                    distance.set(d.toString())
                }
                if (!isPaddingFirst.get()!!) {
                    val d = distance.get().I
                    val p = (l - c * d) / 2
                    padding.set(p.toString())
                }
            }
        }
    }

    fun editOrder(order: Order) {
        id = order.id
        isAddingNew.set(false)
        btnCancelVisible.set(View.VISIBLE)

        val flange = order.flange
        len.set(flange.length.toString())
        wid.set(flange.width.toString())
        if (flange.extraLength != 0) extraLen.set(flange.extraLength.toString())
        if (flange.extraWidth != 0) extraWid.set(flange.extraWidth.toString())
        val position = when (flange.materialSpec) {
            "30" -> 0
            "40" -> 1
            "50" -> 2
            else -> 0
        }
        selectedSpecPosition.set(position)
        actualSpec.set(flange.actualSpec.toString())
        hasRounding.set(flange.hasRounding)
        num.set(order.requiredNumber.toString())
        if (flange.xBigHoleCount != 0 && flange.xSmallHoleCount != 0) {
            holeParamVisibility.set(View.VISIBLE)
            // xBig
            xBigHoles.set(flange.xBigHoleCount.toString())
            xBigHolePadding.set(flange.xBigHolePadding.toString())
            xBigHoleDistance.set(flange.xBigHoleDistance.toString())
            // xSmall
            xSmallHoles.set(flange.xSmallHoleCount.toString())
            xSmallHolePadding.set(flange.xSmallHolePadding.toString())
            xSmallHoleDistance.set(flange.xSmallHoleDistance.toString())
            // xBig
            yBigHoles.set(flange.yBigHoleCount.toString())
            yBigHolePadding.set(flange.yBigHolePadding.toString())
            yBigHoleDistance.set(flange.yBigHoleDistance.toString())
            // xBig
            ySmallHoles.set(flange.ySmallHoleCount.toString())
            ySmallHolePadding.set(flange.ySmallHolePadding.toString())
            ySmallHoleDistance.set(flange.ySmallHoleDistance.toString())
        }
    }

    fun cancelEdit(v: View) {
        id = 0
        isAddingNew.set(true)
        btnCancelVisible.set(View.GONE)
        clearTable()
        toast(v.context, v.context.getString(R.string.canel_edit))
    }

}